﻿#include "OiPCH.hpp"
#include <QtCharts/QDateTimeAxis>

using namespace QtCharts;

namespace Oi
{
    namespace PLScannerCore
    {
        class ValueInDateChartImpl : public Impl<ValueInDateChart>
        {
        public:
            void init();
            void setValue(const QList<qreal> &value);
            void updateTexts();

        public:
            QLineSeries* _line;
            QScatterSeries* _scatter;
            QList<QGraphicsTextItem*> _texts;
            QList<qreal> _values;

            QValueAxis * _axisX;
            QValueAxis * _axisY;
            double _lower;
            double _upper;

        public:
            int _category; // 0，默认) 按小时分类，近24小时；1) 按日分类，近1周； 2）按日分类，近一月；3）按月分类, 近一年
        };

        class ValueInDateChartViewImpl : public Impl<ValueInDateChartView>
        {
    
        public:
            ValueInDateChart* _chart;

        public:
            QGraphicsLineItem* _upperLine;
            QGraphicsLineItem* _lowerLine;
        };

        void ValueInDateChartImpl::init()
        {
            OI_Q(ValueInDateChart);
            q->setTheme((QChart::ChartTheme)PLScannerStyle::ChartDefaultTheme());
            q->setBackgroundVisible(false);
            q->setPlotAreaBackgroundBrush(PLScannerStyle::ChartBgColor());
            q->setPlotAreaBackgroundVisible(true);
            q->layout()->setContentsMargins(0, 0, 0, 0);
            q->setBackgroundRoundness(0);
            q->legend()->setVisible(false);
         
            _line = new QLineSeries();
            _scatter = new QScatterSeries();
            _scatter->setMarkerShape(QScatterSeries::MarkerShapeCircle);
            _scatter->setMarkerSize(5.0);

            q->addSeries(_line);
            q->addSeries(_scatter);

            _axisX = new QValueAxis();
            _axisX->setGridLineVisible(false);
            _axisX->setTickCount(30);
            _axisX->setLabelFormat("%d");
            q->addAxis(_axisX, Qt::AlignBottom);

            _axisY = new QValueAxis();
            _axisY->setGridLineVisible(false);
            _axisY->setTickCount(11);
            _axisY->setRange(0, 100);
            _axisY->setLabelFormat("%d%");
            q->addAxis(_axisY, Qt::AlignLeft);

            _line->attachAxis(_axisX);
            _line->attachAxis(_axisY);

            _scatter->attachAxis(_axisX);
            _scatter->attachAxis(_axisY);
        }

        void ValueInDateChartImpl::setValue(const QList<qreal> &values)
        {
            OI_Q(ValueInDateChart);

            _values = values;

            for(int i = 0; i < values.size(); i++)
            {
                if(i >= _line->count())
                {
                    _line->append(i + 1, values[i]);
                }
                else
                {
                    _line->replace(i, i + 1, values[i]);
                }
            }

            for(int i = values.size(); i < _line->count(); i++)
            {
                _line->remove(i);
            }

            for(int i = 0; i < values.size(); i++)
            {
                if(i >= _scatter->count())
                {
                    _scatter->append(i + 1, values[i]);
                }
                else
                {
                    _scatter->replace(i, i + 1, values[i]);
                }
            }

            for(int i = values.size(); i < _scatter->count(); i++)
            {
                _scatter->remove(i);
            }

            updateTexts();
        }

        void ValueInDateChartImpl::updateTexts()
        {
            OI_Q(ValueInDateChart);

           if (_axisY->labelFormat() == "%d%")
           {
               for (int i = 0; i < _values.size(); i++)
               {
                   if (i >= _texts.size())
                   {
                       QGraphicsTextItem* text = new QGraphicsTextItem(QString::number(qRound(_values[i])) + "%");
                       q->scene()->addItem(text);
                       text->setPos(q->mapToScene(q->mapToPosition(QPointF(i + 1, _values[i] + 5.0))));
                       _texts.append(text);
                   }
                   else
                   {
                       _texts[i]->setPos(q->mapToScene(q->mapToPosition(QPointF(i + 1, _values[i] + 5.0))));
                       _texts[i]->setPlainText(QString::number(qRound(_values[i])) + "%");
                   }
               }
           }
           else
           {
               for (int i = 0; i < _values.size(); i++)
               {
                   if (i >= _texts.size())
                   {
                       QGraphicsTextItem* text = new QGraphicsTextItem(QString::number(_values[i], 'f', 2));
                       q->scene()->addItem(text);
                       text->setPos(q->mapToScene(q->mapToPosition(QPointF(i + 1, _values[i] + 5.0))));
                       _texts.append(text);
                   }
                   else
                   {
                       _texts[i]->setPos(q->mapToScene(q->mapToPosition(QPointF(i + 1, _values[i] + 5.0))));
                       _texts[i]->setPlainText(QString::number(_values[i], 'f', 2));
                   }
               }
           }
            

            for(auto iter = _texts.begin() + _values.size(); iter != _texts.end(); )
            {
                delete ( *iter );
                iter = _texts.erase(iter);
            }
        }

        ValueInDateChart::ValueInDateChart(QGraphicsItem *parent /*= Q_NULLPTR*/, Qt::WindowFlags wFlags /*= Qt::WindowFlags()*/)
            : QChart(parent, wFlags)
        {
            OI_I(ValueInDateChart)->init();
        }

        ValueInDateChart::~ValueInDateChart()
        {
            OI_E(ValueInDateChart);
        }

        void ValueInDateChart::setYFormat(const QString format)
        {
            OI_F(ValueInDateChart);

            d->_axisY->setLabelFormat(format);
        }

        void ValueInDateChart::setYRange(double y1, double y2)
        {
            OI_F(ValueInDateChart);

            d->_axisY->setTickCount(11);
            d->_axisY->setRange(y1, y2);
        }
      

        void ValueInDateChart::setValues(const int category, const QList<double> &values, int range)
        {
            OI_F(ValueInDateChart);
            
            d->setValue(values);

            d->_axisX->setTickCount(range);
            d->_axisX->setRange(1, range);
        }     

        void ValueInDateChart::updateTextPos()
        {
            OI_F(ValueInDateChart);
            d->updateTexts();
        }

        ValueInDateChartView::ValueInDateChartView(QWidget *parent /*= Q_NULLPTR*/)
            : QChartView(parent)
        {
            OI_I(ValueInDateChartView);
            d->_chart = new ValueInDateChart();

            setChart(d->_chart);

            d->_upperLine = new QGraphicsLineItem();
            d->_upperLine->setPen(QPen(Qt::red, 1, Qt::DotLine));

            d->_lowerLine = new QGraphicsLineItem();
            d->_lowerLine->setPen(QPen(Qt::red, 1, Qt::DotLine));

            scene()->addItem(d->_upperLine);
            scene()->addItem(d->_lowerLine);

            d->_upperLine->hide();
            d->_lowerLine->hide();
        }

        
        ValueInDateChartView::ValueInDateChartView(ValueInDateChart *chart, QWidget *parent /*= Q_NULLPTR*/)
            : QChartView(chart, parent)
        {
            OI_I(ValueInDateChartView);

            d->_chart = chart;

            d->_upperLine = new QGraphicsLineItem();
            d->_upperLine->setPen(QPen(Qt::red, 1, Qt::DotLine));

            d->_lowerLine = new QGraphicsLineItem();
            d->_lowerLine->setPen(QPen(Qt::red, 1, Qt::DotLine));

            scene()->addItem(d->_upperLine);
            scene()->addItem(d->_lowerLine);

            d->_lowerLine->setZValue(100);
            d->_upperLine->setZValue(100);

            d->_upperLine->hide();
            d->_lowerLine->hide();
        }

        void ValueInDateChartView::setLimit(double upper, double lower)
        {
            OI_F(ValueInDateChartView);

            d->_chart->setYRange(1.1 * lower - 0.1 * upper,
                1.1 * upper - 0.1 * lower);

            d->_chart->update();

            QPointF p1InChart = QPointF(((QValueAxis*)(d->_chart->axisX()))->min(), lower);
            QPointF p2InChart = QPointF(((QValueAxis*)(d->_chart->axisX()))->max(), lower);
            QPointF p1Pos = d->_chart->mapToPosition(p1InChart);
            QPointF p2Pos = d->_chart->mapToPosition(p2InChart);
            QPointF p1InScene = d->_chart->mapToScene(p1Pos);
            QPointF p2InScene = d->_chart->mapToScene(p2Pos);

            d->_lowerLine->setLine(QLineF(p1InScene, p2InScene));
            d->_lowerLine->show();

            p1InChart = QPointF(((QValueAxis*)(d->_chart->axisX()))->min(), upper);
            p2InChart = QPointF(((QValueAxis*)(d->_chart->axisX()))->max(), upper);
            p1Pos = d->_chart->mapToPosition(p1InChart);
            p2Pos = d->_chart->mapToPosition(p2InChart);
            p1InScene = d->_chart->mapToScene(p1Pos);
            p2InScene = d->_chart->mapToScene(p2Pos);

            d->_upperLine->setLine(QLineF(p1InScene, p2InScene));
            d->_upperLine->show();
        }

        void ValueInDateChartView::resizeEvent(QResizeEvent *event)
        {
            QChartView::resizeEvent(event);
            OI_IMPL()->_chart->updateTextPos();
        }

    }

    

}